/*
 * Copyright (c) GoKeep by gokeep.org. 2022-2023. All rights reserved
 */
package org.gokeep.application.config;

import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.gokeep.common.component.EnvComponent;
import org.gokeep.common.config.properties.SystemConfigProperties;
import org.gokeep.common.document.Company;
import org.gokeep.common.document.Group;
import org.gokeep.common.document.Organization;
import org.gokeep.common.exception.GoKeepException;
import org.gokeep.common.repository.GroupRepository;
import org.gokeep.common.util.SnowflakeIdWorker;
import org.gokeep.communication.demo.TestData;
import org.gokeep.communication.engine.CommunicationEngine;
import org.gokeep.common.document.User;
import org.gokeep.common.repository.CompanyRepository;
import org.gokeep.communication.service.UserService;
import org.mindrot.jbcrypt.BCrypt;
import org.redisson.api.RedissonClient;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.annotation.Configuration;

import java.util.List;
import java.util.Objects;
import java.util.Optional;

import static org.gokeep.common.config.GlobalConfig.*;
import static org.gokeep.common.constant.enums.CachePrefixEnum.REDIS_ORG_TREE_KEY;

@Slf4j
@Configuration
public class SystemInitLoad implements ApplicationRunner {

    @Resource
    private UserService userService;

    @Resource
    private CommunicationEngine communicationEngine;

    @Resource
    private SystemConfigProperties systemConfigProperties;

    @Resource
    private CompanyRepository companyRepository;

    @Resource
    private RedissonClient redissonClient;

    @Resource
    private GroupRepository groupRepository;

    @Resource
    private EnvComponent envComponent;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        // 程序初始化检查
        // 如未初始化，执行数据库、配置文件初始化
        // 检查系统配置
        checkSystemConfig();
        // 启动通信服
        startCommunicationEngine();
        // 初始化组织机构信息
        String companyId = initCompany();
        // 初始化管理员数据
        initSystemUserData(companyId);
        // 初始化测试群组
        initTestGroup();
        // 初始化组织信息
        initOrganization(companyId);
        // 预热
        preheat();
    }

    /**
     * 检查系统配置
     */
    private void checkSystemConfig() {
        assert envComponent.verifyEnvActive() : new GoKeepException("not active system yml config");
    }

    /**
     * 初始化组织机构到缓存
     */
    private void initOrganization(String companyId) {
        if (systemConfigProperties.isFreedomMode()) {
            return;
        }
        Optional<Company> optional = companyRepository.findById(companyId);
        if (optional.isPresent()) {
            Organization organization = optional.get().getOrganizations();
            if (!Objects.isNull(organization)) {
                String redisKey = REDIS_ORG_TREE_KEY.getCacheKey().formatted(companyId);
                redissonClient.getBucket(redisKey).set(organization);
            }
        }
    }

    /**
     * 启动通信引擎服务
     */
    private void startCommunicationEngine() {
        communicationEngine.start();
    }

    /**
     * 系统预热操作
     */
    private void preheat() {
        // 初始化一次SnowFlake生成器
        SnowflakeIdWorker.generateId();
    }

    /**
     * 初始化测试组
     */
    private void initTestGroup() {
        Optional<Group> groupOptional = groupRepository.findById(TestData.INIT_GROUP_ID);
        if (groupOptional.isEmpty()) {
            Group testGroup = TestData.getGroup();
            groupRepository.save(testGroup);
        }
    }

    /**
     * 初始化管理员用户
     */
    private void initSystemUserData(String companyId) {
        User administrator = userService.getUserByUsername(ADMIN_USER_NAME);
        // 已经被初始化过数据
        if (administrator == null) {
            String encryptPwd = BCrypt.hashpw(ADMIN_USER_PASSWORD, BCrypt.gensalt());
            User user = new User().setUsername(ADMIN_USER_NAME).setPassword(encryptPwd).setNickname(ADMIN_NICKNAME).setCompanyId(companyId);
            userService.createUser(user);
        }
        // TODO: 后面需要改为从文件读取
        List<User> users = TestData.generateTestUser().values().stream().toList();
        users.forEach(user -> {
            User testUser = userService.getUserByUsername(user.getUsername());
            if (testUser == null) {
                user.setPassword(BCrypt.hashpw(user.getPassword(), BCrypt.gensalt()));
                user.setCompanyId(companyId);
                userService.createUser(user);
            }
        });
    }

    /**
     * 初始化组织信息
     */
    //TODO: 目前仅开启两种模式，一种是自由模式，无企业信息，一种是非自由模式
    private String initCompany() {
        boolean isFreedomMode = systemConfigProperties.isFreedomMode();
        log.info("Application start system mode is: [{}]", isFreedomMode);
        if (isFreedomMode) {
            return null;
        }
        Company company = companyRepository.findByName(DEFAULT_COMPANY_NAME);
        // 初始化企业信息，主要用于测试
        if (company == null) {
            Company initCompany = new Company();
            initCompany.setCompanyId(TestData.INIT_COMPANY_ID);
            initCompany.setName(DEFAULT_COMPANY_NAME);
            Organization organization = new Organization();
            organization.setName("");
            return companyRepository.save(initCompany).getCompanyId();
        }
        return company.getCompanyId();
    }
}
